﻿using Microsoft.Extensions.Caching.Memory;
using System;
using System.Threading.Tasks;
using X23.Util.SerializationUtil;
using static X23.Util.CacheUtil.CacheConst;

namespace X23.Util.CacheUtil
{
    public class MemoryCacheService : ICacheService
    {
        private readonly IMemoryCache _memoryCache;
        private readonly object locker = new();

        public MemoryCacheService(IMemoryCache memoryCache)
        {
            _memoryCache = memoryCache;
        }
        public async Task<string> GetAsync(string key)
        {
            var result = _memoryCache.Get(key).ToJson();
            return await Task.FromResult(result);
        }
        public async Task<string> GetOrCreateAsync(string key, Func<Task<string>> func, int minutes = 60, ExpirationType expirationType = ExpirationType.AbsoluteExpiration)
        {
            var result = await _memoryCache.GetOrCreateAsync(key,
                async cacheEntry =>
                {
                    if (expirationType == ExpirationType.AbsoluteExpiration)
                    {
                        cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(minutes);
                    }
                    else
                    {
                        cacheEntry.SlidingExpiration = TimeSpan.FromMinutes(minutes);
                    }

                    return await func();
                });
            return result;
        }
        public async Task<int> IncrementAsync(string key, int inc = 0)
        {
            var result = 0;
            lock (locker)
            {
                result = _memoryCache.GetOrCreate(key,
                    cacheEntry =>
                    {
                        return 0;
                    });
                result += inc;
            }
            return await Task.FromResult(result);
        }

        public async Task<bool> RemoveAsync(string key)
        {
            if (_memoryCache.TryGetValue(key, out _))
            {
                _memoryCache.Remove(key);
            }
            return await Task.FromResult(true);
        }

        public async Task<bool> SetAsync(string key, string val, int minutes = 60, ExpirationType expirationType = ExpirationType.AbsoluteExpiration)
        {
            var result = false;
            if (_memoryCache.TryGetValue(key, out _))
            {
                var cacheEntryOptions = new MemoryCacheEntryOptions();
                if (expirationType == ExpirationType.AbsoluteExpiration)
                {
                    cacheEntryOptions.SetAbsoluteExpiration(TimeSpan.FromMinutes(minutes));
                }
                else
                {
                    cacheEntryOptions.SetSlidingExpiration(TimeSpan.FromMinutes(minutes));
                }
                _memoryCache.Set(key, val);
                result = true;
            }
            return await Task.FromResult(result);
        }
    }
}
